<template>
  <view class="slider-container">
    <view class="slider-track" ref="sliderTrack" :style="trackStyle">
      <view class="slider-bar" :style="barStyle"></view>
      <view
        class="slider-thumb"
        :style="thumbStyle"
        @touchstart="onTouchStart"
        @touchmove="onTouchMove"
        @touchend="onTouchEnd"
      ></view>
    </view>
    <view class="slider-marks">
      <view
        v-for="(mark, idx) in marksWithStyle"
        :key="idx"
        class="slider-mark"
        :style="mark.style"
      >
        <text class="slider-mark-label">{{ mark.label }}</text>
      </view>
    </view>
  </view>
</template>

<script>
export default {
	name: 'SdSlider',
	props: {
		min: { type: Number, default: 0 },
		max: { type: Number, default: 100 },
		step: { type: Number, default: 1 },
		value: { type: Number, default: 0 },
		marks: {
			type: Array,
			default: () => [
				{ value: 0, label: '0' },
				{ value: 10, label: '10' },
				{ value: 15, label: '15' },
				{ value: 20, label: '20' },
				{ value: 50, label: '50' },
				{ value: 100, label: '不限' },
			],
		},
	},
	data() {
		return {
			sliderWidth: 0,
			dragging: false,
			currentValue: this.value,
		};
	},
	computed: {
		percent() {
			return ((this.currentValue - this.min) / (this.max - this.min)) * 100;
		},
		trackStyle() {
			return 'width: 100%; height: 16rpx; background: #e5e5e5; border-radius: 8rpx; position: relative;';
		},
		barStyle() {
			return 'width: ' + this.percent + '%; height: 100%; background: #2196f3; border-radius: 8rpx; position: absolute; left: 0; top: 0;';
		},
		thumbStyle() {
			return 'left: calc(' + this.percent + '% - 20rpx); width: 40rpx; height: 40rpx; background: #2196f3; border-radius: 50%; position: absolute; top: 50%; transform: translateY(-50%);';
		},
		marksWithStyle() {
			return this.marks.map(mark => {
				const percent = ((mark.value - this.min) / (this.max - this.min)) * 100;
				if (mark.value === this.min) {
					return {
						...mark,
						style: 'left: 0; position: absolute; top: 18rpx; text-align: left; transform: none;'
					};
				}
				if (mark.value === this.max) {
					return {
						...mark,
						style: 'right: 0; left: auto; position: absolute; top: 18rpx; text-align: right; transform: none;'
					};
				}
				return {
					...mark,
					style: 'left: calc(' + percent + '%); position: absolute; top: 18rpx; text-align: center; transform: translateX(-50%);'
				};
			});
		},
	},
	watch: {
		value(val) {
			this.currentValue = val;
		},
	},
	mounted() {
		this.getSliderWidth();
	},
	methods: {
		getSliderWidth(cb) {
			const query = uni.createSelectorQuery().in(this);
			query.select('.slider-track').boundingClientRect(data => {
				this.sliderWidth = data.width;
				if (cb) cb();
			}).exec();
		},
		onTouchStart() {
			this.dragging = true;
			// 拖动开始时重新获取宽度，保证准确
			this.getSliderWidth();
		},
		onTouchMove(e) {
			if (!this.dragging) return;
			if (!this.sliderWidth) return; // 防止为0
			const touch = e.touches[0];
			// 小程序端用 pageX
			let sliderLeft = 0;
			// #ifdef H5
			if (this.$refs.sliderTrack && this.$refs.sliderTrack.$el && this.$refs.sliderTrack.$el.getBoundingClientRect) {
				sliderLeft = this.$refs.sliderTrack.$el.getBoundingClientRect().left;
			}
			// #endif
			// #ifndef H5
			// 小程序端用 selectorQuery
			// 已经通过 getSliderWidth 获取宽度，sliderLeft 只能通过 selectorQuery 获取
			// 这里假设 sliderTrack 靠左对齐，pageX 可直接用
			// #endif
			let x = touch.pageX - sliderLeft;
			if (x < 0) x = 0;
			if (x > this.sliderWidth) x = this.sliderWidth;
			const percent = x / this.sliderWidth;
			let value = this.min + percent * (this.max - this.min);
			value = Math.round(value / this.step) * this.step;
			value = Math.max(this.min, Math.min(value, this.max));
			if (value !== this.currentValue) {
				this.currentValue = value;
				this.$emit('input', value);
				this.$emit('change', value);
			}
		},
		onTouchEnd() {
			this.dragging = false;
		},
	},
};
</script>

<style scoped>
.slider-container {
  width: 100%;
  padding: 30rpx 0 0 0;
}
.slider-track {
  width: 100%;
  height: 16rpx;
  background: #e5e5e5;
  border-radius: 8rpx;
  position: relative;
}
.slider-bar {
  height: 100%;
  background: #2196f3;
  border-radius: 8rpx;
  position: absolute;
  left: 0;
  top: 0;
}
.slider-thumb {
  width: 40rpx;
  height: 40rpx;
  background: #2196f3;
  border-radius: 50%;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
}
.slider-marks {
  width: 100%;
  position: relative;
  height: 60rpx;
  /* margin-top: 12rpx; */
}
.slider-mark {
  position: absolute;
  top: 24rpx;
  width: 80rpx;
  left: 0;
  text-align: center;
  color: #444;
  font-size: 24rpx;
  transform: translateX(-50%);
}
.slider-mark-label {
  display: block;
}
</style>
